import axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type AxiosResponse,
  type InternalAxiosRequestConfig
} from 'axios'
import { ApiResponse } from '@/types/api'

// 扩展配置类型以支持metadata
interface ExtendedAxiosRequestConfig extends InternalAxiosRequestConfig {
  metadata?: {
    startTime: Date
  }
}

class ApiClient {
  private instance: AxiosInstance
  private baseURL: string

  constructor() {
    this.baseURL = '/api/v1'
    
    this.instance = axios.create({
      baseURL: this.baseURL,
      timeout: 30000,
      headers: {
        'Content-Type': 'application/json',
      },
    })

    this.setupInterceptors()
  }

  private setupInterceptors() {
    // Request interceptor
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // Add auth token if available
        const token = this.getAuthToken()
        if (token && config.headers) {
          config.headers.Authorization = `Bearer ${token}`
        }

        // Add request timestamp for debugging
        const extendedConfig = config as ExtendedAxiosRequestConfig
        extendedConfig.metadata = { startTime: new Date() }

        return config
      },
      (error: unknown) => {
        return Promise.reject(error)
      }
    )

    // Response interceptor
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        // Log response time in development
        if (import.meta.env.DEV) {
          const extendedConfig = response.config as ExtendedAxiosRequestConfig
          if (extendedConfig.metadata) {
            const endTime = new Date()
            const duration = endTime.getTime() - extendedConfig.metadata.startTime.getTime()
            console.log(`API ${response.config.method?.toUpperCase()} ${response.config.url}: ${duration}ms`)
          }
        }

        return response
      },
      async (error: any) => {
        const originalRequest = error.config

        // Handle 401 errors (unauthorized)
        if (error.response?.status === 401 && !originalRequest._retry) {
          originalRequest._retry = true

          try {
            // Try to refresh token
            const refreshToken = this.getRefreshToken()
            if (refreshToken) {
              const response = await this.post('/auth/refresh', { refreshToken })
              const { accessToken } = response.data

              // Update stored token
              this.setAuthToken(accessToken)

              // Retry original request
              originalRequest.headers.Authorization = `Bearer ${accessToken}`
              return this.instance(originalRequest)
            }
          } catch (refreshError) {
            // Refresh failed, redirect to login
            this.clearAuthTokens()
            window.location.href = '/login'
            return Promise.reject(refreshError)
          }
        }

        // Handle network errors
        if (!error.response) {
          error.message = 'Network error. Please check your connection.'
        }

        return Promise.reject(error)
      }
    )
  }

  // Auth token management
  private getAuthToken(): string | null {
    return localStorage.getItem('accessToken')
  }

  private getRefreshToken(): string | null {
    return localStorage.getItem('refreshToken')
  }

  private setAuthToken(token: string): void {
    localStorage.setItem('accessToken', token)
  }

  private clearAuthTokens(): void {
    localStorage.removeItem('accessToken')
    localStorage.removeItem('refreshToken')
  }

  // HTTP methods
  async get<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.instance.get(url, config)
    return response.data
  }

  async post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.instance.post(url, data, config)
    return response.data
  }

  async put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.instance.put(url, data, config)
    return response.data
  }

  async patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.instance.patch(url, data, config)
    return response.data
  }

  async delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.instance.delete(url, config)
    return response.data
  }

  // File upload with progress
  async upload<T = any>(
    url: string,
    file: File,
    onProgress?: (progress: number) => void,
    additionalData?: Record<string, any>
  ): Promise<ApiResponse<T>> {
    const formData = new FormData()
    formData.append('file', file)
    
    if (additionalData) {
      Object.entries(additionalData).forEach(([key, value]) => {
        formData.append(key, value)
      })
    }

    const response = await this.instance.post(url, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      onUploadProgress: (progressEvent) => {
        if (onProgress && progressEvent.total) {
          const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          onProgress(progress)
        }
      },
    })

    return response.data
  }

  // Download file
  async download(url: string, filename?: string): Promise<void> {
    const response = await this.instance.get(url, {
      responseType: 'blob',
    })

    // Create download link
    const blob = new Blob([response.data])
    const downloadUrl = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = filename || 'download'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(downloadUrl)
  }

  // Set auth tokens
  setTokens(accessToken: string, refreshToken: string): void {
    localStorage.setItem('accessToken', accessToken)
    localStorage.setItem('refreshToken', refreshToken)
  }

  // Clear auth tokens
  clearTokens(): void {
    this.clearAuthTokens()
  }

  // Get current auth status
  isAuthenticated(): boolean {
    return !!this.getAuthToken()
  }

  // Create request with custom config
  createRequest(config: AxiosRequestConfig) {
    return this.instance(config)
  }

  // Get base URL
  getBaseURL(): string {
    return this.baseURL
  }
}

// Create singleton instance
export const apiClient = new ApiClient()

// Export types for use in other files
export type { AxiosRequestConfig, AxiosResponse }
